package cn.edu.hqu.pre;

import org.uma.jmetal.problem.permutationproblem.impl.AbstractIntegerPermutationProblem;
import org.uma.jmetal.solution.permutationsolution.PermutationSolution;

import java.util.HashMap;
import java.util.Map;

/**
 * 定义“两日游旅游线路”问题
 *
 * @author 洪佳森
 * @date 2023-12-11
 */
public class TwoDayTripRouteProblem extends AbstractIntegerPermutationProblem {

    /**
     * 节点数
     */
    private final int numberOfCities;

    /**
     * 距离矩阵
     */
    private double[][] distanceMatrix;

    /**
     * 旅途时间矩阵
     */
    private double[][] travelTimeMatrix;

    /**
     * 游玩时间矩阵
     */
    private double[] playMatrix;

    /**
     * 遗产点评价矩阵
     */
    private double[] rankMatrix;

    /**
     * 遗产点评价映射表
     */
    private final Map<String, Double> rankMap = new HashMap<>();

    public TwoDayTripRouteProblem(int numberOfCities) {
        this.numberOfCities = numberOfCities;
    }

    @Override
    public int numberOfVariables() {
        return numberOfCities;
    }

    @Override
    public int numberOfObjectives() {
        return 2;
    }

    @Override
    public int numberOfConstraints() {
        return 1;
    }

    @Override
    public String name() {
        return "两日游旅游线路";
    }

    @Override
    public PermutationSolution<Integer> evaluate(PermutationSolution<Integer> solution) {
        double fitness1 = 0.0;
        double fitness2 = 0.0;
        double travelTimeTotal = 0.0;
        for (int i = 0; i < (numberOfCities - 1); i++) {
            int x = solution.variables().get(i);
            int y = solution.variables().get(i+1);

            fitness1 += distanceMatrix[x][y];
            fitness2 -= rankMatrix[x];
            travelTimeTotal += travelTimeMatrix[x][y];
        }
        int firstCity = solution.variables().get(0);
        int lastCity = solution.variables().get(numberOfCities - 1);
        fitness1 += distanceMatrix[firstCity][lastCity];
        fitness2 -= rankMatrix[lastCity];
        travelTimeTotal += travelTimeMatrix[firstCity][lastCity];

        solution.objectives()[0] = fitness1;
        solution.objectives()[1] = fitness2;


        // 限制旅途时间和游玩时间小于24小时
        double constraint = 0.0;
        for (int i = 0; i < numberOfCities; i++) {
            int x = solution.variables().get(i);
            constraint += playMatrix[x];
        }
        solution.constraints()[0] = 16 * 60 - (constraint + travelTimeTotal);

        return solution;
    }

    @Override
    public PermutationSolution<Integer> createSolution() {
        return new MyIntegerPermutationSolution(length(), numberOfObjectives(), numberOfConstraints()) ;
    }

    public void setDistanceMatrix(double[][] distanceMatrix) {
        this.distanceMatrix = distanceMatrix;
    }

    public void setTravelTimeMatrix(double[][] travelTimeMatrix) {
        this.travelTimeMatrix = travelTimeMatrix;
    }

    public void setPlayMatrix(double[] playMatrix) {
        this.playMatrix = playMatrix;
    }

    public void setRankMatrix(double[] rankMatrix) {
        this.rankMatrix = rankMatrix;
    }

    public Map<String, Double> getRankMap() {
        return rankMap;
    }

    public void setRank(String name, Double rank) {
        rankMap.put(name, rank);
    }
}
